﻿using System.Threading;
using System;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Xml.Serialization;
using System.IO;
using System.Text.RegularExpressions;
using TravianHelper.hero;
using TravianHelper.app;
using TravianHelper.village;
using TravianHelper.tools;
using TravianHelper.oasis;

namespace TravianHelper
{
    public partial class Form2 : Form
    {
        bool startPressed = false;
        
        TravianApplicationContext context = new TravianApplicationContext();

        public Form2()
        {
            InitializeComponent();
        }

        public void reloadComboBoxVillage()
        {
            comboBoxVillage.Items.Clear();
            for (int i = 0; i < TravianApplicationContext.villages.Count; i++)
            {
                Village village = (Village)TravianApplicationContext.villages[i];
                comboBoxVillage.Items.Add(village.name);
            }
        }

        private void loginlogout()
        {
            if (TravianApplicationContext.loggedIn == false)
            {
                if (TravianApplicationContext.adapter.login(textBoxUsername.Text, textBoxPassword.Text))
                {
                    TravianApplicationContext.loggedIn = true;
                    buttonLogin.Text = "logout";
                    buttonStart.Enabled = true;
                    TravianApplicationContext.loadData();
                    reloadComboBoxVillage();                  
                }
                else
                {
                    MessageBox.Show("Log in failed");
                }
            }
            else
            {
                TravianApplicationContext.adapter.logout();
                TravianApplicationContext.loggedIn = false;
            }
        }

        private void buttonLogin_Click(object sender, EventArgs e)
        {
            loginlogout();
        }

        private void Form2_Load(object sender, EventArgs e)
        {
            TravianApplicationContext.mainForm = this;
            reloadComboBoxVillage();
        }

        private void buttonAddVillage_Click(object sender, EventArgs e)
        {
            Village village = new Village();
            village.name = comboBoxVillage.Text;
            TravianApplicationContext.villages.Add(village);
            reloadComboBoxVillage();
        }

        private void buttonRemoveVillage_Click(object sender, EventArgs e)
        {
            int i = comboBoxVillage.SelectedIndex;
            Village village = (Village)TravianApplicationContext.villages[i];
            string name = village.name;
            if (MessageBox.Show("Do you want to remove village \"" + name + "\" ?", "Travian Helper",
         MessageBoxButtons.YesNo, MessageBoxIcon.Question)
         == DialogResult.Yes)
            {
                TravianApplicationContext.villages.RemoveAt(comboBoxVillage.SelectedIndex);
                reloadComboBoxVillage();
            }
        }

        private void comboBoxVillage_SelectedIndexChanged(object sender, EventArgs e)
        {
            int i = comboBoxVillage.SelectedIndex;
            Village village = (Village)TravianApplicationContext.villages[i];
            VillageForm villageForm = new VillageForm(false);
            villageForm.setVillage(village);
            villageForm.Show();


        }

        private void buttonSave_Click(object sender, EventArgs e)
        {
            int i = comboBoxVillage.SelectedIndex;
            Village village = (Village)TravianApplicationContext.villages[i];

            reloadComboBoxVillage();
            comboBoxVillage.SelectedIndex = i;
        }


        private void Form2_FormClosing(object sender, FormClosingEventArgs e)
        {
            Properties.Settings.Default.Save();
            Util.SerializeArrayList(TravianApplicationContext.villages, "data.xml");
            Util.SerializeArrayList(new ArrayList(TravianApplicationContext.oasisPool.Values), "oasisPool.xml");
        }

        private void buttonStart_Click(object sender, EventArgs e)
        {
            if (!startPressed)
            {
                startPressed = true;
                buttonStart.Text = "Stop";
                sendTroopBackgroundWorker.RunWorkerAsync();
            }
            else
            {
                startPressed = false;
                buttonStart.Text = "Start";
                
                /*
              
                timer1.Interval = minInterval;
                buttonStart.Text = "Stop";
                timer1.Start();
                doTick();
                 * */
            }
        }

       

      
       

        private void button1_Click(object sender, EventArgs e)
        {
           // MessageBox.Show(TravianApplicationContext.adapter.getOasisDefend(-18, 14, false).ToString());
            /*try
            {
                //
                string[] i = new string[] { };
                MessageBox.Show(i[1]);
            }
            catch (Exception ex)
            {
                int count = TravianApplicationContext.errors.Count;
                TravianApplicationContext.errors.Add(count + " " + ex.Message, ex.ToString());
                listViewLog.Items.Add(count + " " + ex.Message);
            }*/
        }





        private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            try
            {
                toolStripProgressBar1.Value = e.ProgressPercentage * 100 / TravianApplicationContext.allOasis.Count;
                toolStripStatusLabel1.Text = e.ProgressPercentage + "/" + TravianApplicationContext.allOasis.Count;
            }
            catch (Exception ex)
            {
            }
        }


        private void AddListView(string[] items)
        {
            // InvokeRequired required compares the thread ID of the
            // calling thread to the thread ID of the creating thread.
            // If these threads are different, it returns true.
            if (this.listViewTarget.InvokeRequired)
            {
                AddListViewCallback d = new AddListViewCallback(AddListView);
                this.Invoke(d, new object[] { items });
            }
            else
            {
                listViewTarget.Items.Add(new ListViewItem(items));
            }
        }
        delegate void AddListViewCallback(string[] items);


        private void buttonSort_Click(object sender, EventArgs e)
        {
            int i = comboBoxVillage.SelectedIndex;
            Village village = (Village)TravianApplicationContext.villages[i];

        }

        private void buttonShuffle_Click(object sender, EventArgs e)
        {
            int i = comboBoxVillage.SelectedIndex;
            Village village = (Village)TravianApplicationContext.villages[i];

        }

        private void manageHeroToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (TravianApplicationContext.loggedIn)
            {
                TravianApplicationContext.heroPopup.ShowDialog();
            }
            else
                MessageBox.Show("Must login first");
        }

        private void addVillageToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Village village = new Village();
            village.name = comboBoxVillage.Text;

            VillageForm villageForm = new VillageForm(true);
            villageForm.setVillage(village);
            villageForm.Show();
        }

        private void listViewLog_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (listViewLog.SelectedItems.Count > 0)
            {
                String message = (string)TravianApplicationContext.errors[listViewLog.SelectedItems[0].Text];
                MessageBox.Show(message);
            }
        }

        private void soloHero(Zone zone, HeroInfo hero)
        {
            HeroConfig heroConfig = TravianApplicationContext.heroConfig;
            // do adventure
            if (hero.health >= heroConfig.minHealthWithTroop && hero.available && heroConfig.autoAdventure)
            {
                bool adventure = TravianApplicationContext.adapter.adventure();
                if (adventure) hero.available = false;
            }

            // solo oasis

        }
        private void sendTroop(Oasis zone)
        {
            TravianApplicationContext.oasisManager.updateNearestVillage(zone, TravianApplicationContext.villages);
            // find the nearest village
            double distance2Nearest = zone.distance2Nearest;
            Village nearestVillage = zone.nearestVillage;
            

            // for each type of troop, find the appropriate one
            for (int i = 0; i < nearestVillage.troops.Count; i++)
            {
                Troop troop = (Troop)nearestVillage.troops[i];
                if (distance2Nearest > troop.maxDistance + 1) // too far, skip this kinda troop
                    continue;
                else
                {
                    int id = troop.id;
                    string name = troop.name;
                    
                   // int nEachWave = troop.number_each_wave;
                    // int minTroopEachWave = troop.minNumberEachWave;
                    int troopStay = troop.stay;

                   // Int32 troopToGo = new Random().Next(minTroopEachWave, nEachWave + 1);
                    // check history with last send time & troop
                    DateTime nextArrivalTime = DateTime.Now.AddHours(distance2Nearest / troop.speed);// assume that oasis production is 100/hour

                    int estimatedRessources = TravianApplicationContext.oasisManager.calculateRessourcesInOasis(zone, nextArrivalTime);
                    int troopToGo =  estimatedRessources/troop.carry   ;
                    if (troopToGo >= 2) // mostly, you need at least 2 troop to raid an oasis
                    {
                        troop.numberInTheVillage = TravianApplicationContext.adapter.selectCity(nearestVillage.id, troop.name);
                        if (troop.numberInTheVillage - troopToGo > troopStay )
                        {                        
                            string result = TravianApplicationContext.adapter.attack(zone.x, zone.y, troop.id, troopToGo, nearestVillage.id, false);
                            zone.status = result;
                            zone.troopArrivalTime = nextArrivalTime;
                            break;
                        }
                        
                    }
                    else
                    {
                        continue; // done, break
                    }
 
                    
                }


            }

        }

        private void sendTroopBackgroundWorker_DoWork(object sender, DoWorkEventArgs e)
        {
            Int32 maxInterval = Convert.ToInt32(textBoxInterval.Text) * 1000;
            Int32 minInterval = Convert.ToInt32(txtBoxMinInterval.Text) * 1000;
            while (true) // forever
            {            
                if (!startPressed && !TravianApplicationContext.accountBlocked) // stop pressed
                {
                    Thread.Sleep(new Random().Next(20000)); // stop for 20 s so user can do things
                    continue;
                }
                try
                {
                    // 1. Login if not logged yet
                    if (TravianApplicationContext.loggedIn == false)
                        loginlogout();

                    // 2. loop through all declared oasis
               
                    /* count troop for each village
                    for (int j = 0; j < TravianApplicationContext.villages.Count; j++)
                    {
                        Village village = (Village)TravianApplicationContext.villages[j];
                        // for each type of troop
                        for (int i = 0; i < village.troops.Count; i++)
                        {
                            Troop troop = (Troop)village.troops[i];
                            troop.numberInTheVillage = TravianApplicationContext.adapter.selectCity(village.id, troop.name);
                        }
                    }*/

                    // for oasis
                    foreach (Oasis zone in TravianApplicationContext.oasisPool.Values)
                    {
                        if (zone.occupied)
                            continue;
                        // oasis DEF point
                        TravianApplicationContext.adapter.updateOasisInfo(zone, false);

                        if (zone.occupied) // again for recently occupied
                            continue;

                        if (zone.defend > 0)
                            soloHero(zone, TravianApplicationContext.heroManager.loadHeroInfo());
                        else
                            sendTroop(zone);
                    }

                    // logout
                    if (TravianApplicationContext.loggedIn)
                        loginlogout();

                    Thread.Sleep(new Random().Next((maxInterval +minInterval)/2));
                }

                catch (Exception ex)
                {
                    int count1 = TravianApplicationContext.errors.Count;
                    TravianApplicationContext.errors.Add(count1 + " " + ex.Message, ex.ToString());
                    addLog(count1 + " " + ex.Message);
                }
            }

        }

        private void addLog (string content)
        {
        //    listViewLog.Items.Add(content);
        }

        private void findOasisToolStripMenuItem_Click(object sender, EventArgs e)
        {
            System.Threading.Thread newThread = new System.Threading.Thread(new UtilTool().getOasisMap);
            newThread.Start();
        }

        private void findElephanToolStripMenuItem_Click(object sender, EventArgs e)
        {

        }

        private void findNatarsToolStripMenuItem_Click(object sender, EventArgs e)
        {
            FindNatarsForm form = new FindNatarsForm();
            form.Show();
           
        }

        private void natarsToolStripMenuItem_Click(object sender, EventArgs e)
        {
            SearchAddNatars2FarmList form = new SearchAddNatars2FarmList();
            form.Show();
        }

        private void oasisPoolToolStripMenuItem_Click(object sender, EventArgs e)
        {
            OasisPool form = new OasisPool();
            form.Show();
        }

        private void testSerializeToolStripMenuItem_Click(object sender, EventArgs e)
        {
            ArrayList zones = new ArrayList();
            zones.Add(new Zone());
            zones.Add(new Zone());
            zones.Add(new Zone());
            Util.SerializeArrayList(zones, "oasis1.xml");

            ArrayList zones1 = Util.DeSerializeArrayList("oasis1.xml");
            Zone zone = (Zone)zones1[0];
        }

    }
}
